package cn.edu.fudan.rule;

import cn.edu.fudan.type.Pattern;
import cn.edu.fudan.type.Rule;
import cn.edu.fudan.type.WaveletPerOrder;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by 80494 on 2017/4/6.
 */
public class RuleGeneration {
    public List<Rule> RuleGeneration(List<WaveletPerOrder> traindataset, double minsupport, double minconfidence, int maxgap, int kclass) {
        //double support =0.0;

        List<List<Pattern>> L = new ArrayList<>();


        List<Pattern> patterns = new ArrayList<>();

        List<Rule> R = new ArrayList<>();
        List<Integer> series = new ArrayList<>();
        List<List<Integer>> manyseries = new ArrayList<>();
        int order = 0;

        //生成满足支持度的2-pattern

        for (int k = 0; k < traindataset.size(); k++) {   //记录数
            for (int o = 1; o < traindataset.get(k).getDseries().size(); o++) { //层数
                //series.addAll(traindataset.get(k).getDseries().get())
                series = (traindataset.get(k).getDseries().get(o));
                for (int index = 0; index < series.size(); index++) {
                    for (int gap = 0; gap < maxgap; gap++) {
                        if (index + gap + 1 >= series.size()) break;
                        Pattern pattern = new Pattern();
                        double support = 0.0;
                        pattern.getDseries().add(series.get(index)); //第一个位置
                        pattern.getDseries().add(series.get(index + gap + 1)); //第二个位置
                        pattern.getGap().add(0, gap);//第一个间隔
                        pattern.setOrder(o);//第几层
                        for (int number = 0; number < traindataset.size(); number++) {
                            if (traindataset.get(number).getDseries().size() <= o) continue;
                            if (PatternIsSubpatternOfSeries(pattern, traindataset.get(number).getDseries().get(o), o)) {
                                pattern.getSubpatternseriesindex().add(number);
                                support++;
                            }
                        }
                        pattern.setSuport((double) support / (double) (traindataset.size()));
                        boolean sig=false;
                        for(Pattern x:patterns){//去重
                            //System.out.println(x.getDseries().equals(c.getDseries())+" "+ x.getGap().equals(c.getGap())+" "+ (x.getOrder()==c.getOrder()) + " "+sig );
                            sig = x.getDseries().equals(pattern.getDseries()) && x.getGap().equals(pattern.getGap())
                                    && x.getOrder()==pattern.getOrder();
                            //System.out.println(" " +sig);
                            if (sig) break;
                        }
                        if (patterns.contains(pattern)) continue;  //去重
                        if (pattern.getSuport() > minsupport) {
                            patterns.add(pattern);
                            if (L.size() == 0) {
                                L.add(0, patterns);
                            } else {
                                L.set(0, patterns);  //文中的L2
                            }
                        }
                    }
                }
            }
        }

        //series =  traindataset.get(0).getDseries().get(order);//为了得到离散化后的长度

        //for (int record = 0; record < traindataset.size(); record++) {
        //for (order = 1; order.)
        //}


        /*for (int record = 0; record < traindataset.size(); record++) {

            for (order = 1; order < maxorder; order++) {

                for (int gap = 1; gap <= maxgap; gap++) {

                    for (int i = 0; i < traindataset.get(record).getDseries().get(order).size(); i++) {
                        System.out.println(order + " " + i + " " + record);
                        Pattern P = new Pattern();
                        double support = 0.0;
                        if ((i + gap + 1) > traindataset.get(record).getDseries().get(order).size()) break;
                        P.getDseries().add(0, traindataset.get(record).getDseries().get(order).get(i)); //第一个位置
                        P.getDseries().add(0, traindataset.get(record).getDseries().get(order).get(i + gap));//第二个位置
                        P.getGap().add(0, gap); //GAP
                        P.setOrder(order); //第几层
                        for (int j = 0; j < traindataset.size(); j++) {
                            //series =  traindataset.get(j).getDseries().get(order);
                            //series.add(traindataset.get(j).getDseries().get(order).get(i));

                            if (PatternIsSubpatternOfSeriesAGap(P, series, order, gap)) {
                                support++;
                            }
                        }
                        P.setSuport(support / traindataset.size());
                        if (P.getSuport() >= minsupport) {
                            patterns.add(P);
                            if (L.size() == 0) {
                                L.add(0, patterns);
                            } else {
                                L.set(0, patterns);  //文中的L2
                            }
                        }

                    }
                }
            }
        }
        */
        int l = 0;


        //boolean flag = L.get(l).isEmpty();

        //while (!L.get(l).isEmpty() && !L.isEmpty()) {//generate all pattern which has up of minsupport,for k-pattern to (k+1)-pattern
        while (!L.isEmpty()) {//generate all pattern which has up of minsupport,for k-pattern to (k+1)-pattern
            //for (Pattern a : L.get(l)) {
            //    for (Pattern b : L.get(l)) {
            List<Pattern> lkplus1 = new ArrayList<>();
            for(int i=0;i<L.get(l).size();i++){
                for(int j=i;j<L.get(l).size();j++){
                    Pattern  a = new Pattern();
                    Pattern  b = new Pattern();
                    a.setOrder(L.get(l).get(i).getOrder());
                    b.setOrder(L.get(l).get(j).getOrder());
                    a.getDseries().addAll(L.get(l).get(i).getDseries());
                    b.getDseries().addAll(L.get(l).get(j).getDseries());
                    a.getGap().addAll(L.get(l).get(i).getGap());
                    b.getGap().addAll(L.get(l).get(j).getGap());

                    //System.out.println(b.gbtDseries().size()+" 1"+b.getGap().size());
                    if (!PatternCanBeJoin(a, b)) continue;
                    //System.out.println(b.getDseries().size()+"2 "+b.getGap().size());
                    Pattern c = PatternJoin(a, b);

                    double supportkplus1 = 0;
                    for (int d = 0; d < traindataset.size(); d++) {
                        if (traindataset.get(d).getDseries().size() <= a.getOrder()) continue;
                        //System.out.println(traindataset.get(d).getDseries().get(a.getOrder()).size()+" "+c.getDseries().size()+" "+d+" "+a.getOrder());
                        if (PatternIsSubpatternOfSeries(c, traindataset.get(d).getDseries().get(a.getOrder()), a.getOrder())) {
                            supportkplus1++;
                            c.getSubpatternseriesindex().add(d);//记录包含c子序列的所有序列
                        }
                    }
                    c.setSuport((double) supportkplus1 / (double) traindataset.size());


                      //是否重复的标志位

                    if (c.getSuport() >= minsupport) {
                        boolean sig=false;
                        for(Pattern x:lkplus1){//去重
                            //System.out.println(x.getDseries().equals(c.getDseries())+" "+ x.getGap().equals(c.getGap())+" "+ (x.getOrder()==c.getOrder()) + " "+sig );
                            sig = x.getDseries().equals(c.getDseries()) && x.getGap().equals(c.getGap())
                                    && x.getOrder()==c.getOrder();
                            //System.out.println(" " +sig);
                            if (sig) break;
                        }

                        if (!sig){
                            lkplus1.add(c);
                        }
                        //L.get(l+1).add(c);  //文中的Lk+1
                    }
                }
            }
            l++;
            if(lkplus1.size()==0)break;
            L.add(l,lkplus1);
        }


        for (List<Pattern> alist : L) { //create all rule that is satisfied with required confidence
            for (Pattern p : alist) {
                for (int s = 0; s < kclass; s++) {
                    Rule rule = new Rule();
                    double confidence=0.0;
                    double posi = 0.0;
                    double nega =0.0;
                    rule.setLabel(s);
                    for (int t = 0; t < p.getSubpatternseriesindex().size(); t++) {
                        int h= traindataset.get(p.getSubpatternseriesindex().get(t)).getLabel();
                       // System.out.println(traindataset.get(t).getLabel()+" "+s+" "+h+" "+t);

                        if (h==s) {
                            posi++;
                        }else {
                            nega++;
                        }
                    }
                    confidence=(posi / (posi+nega));
                    p.setConfidence(confidence);
                    if (confidence >= minconfidence) {
                        rule.setPattern(p);
                        rule.setConfidence(confidence);
                        rule.setSupport(p.getSuport());
                        R.add(rule);
                    }
                }
            }
        }


        return R;



        /*for (int order = 0; order < maxorder; order++) {
            series = traindataset.getDseries().get(order);
            for (int gap = 0; gap <= maxgap; gap++) {
                for (int i = 0; i < series.size(); i++) {
                    if ((i+gap)>series.size()) break;
                    P.getDseries().set(0,series.get(i));
                    P.getDseries().set(0,series.get(i+gap));
                    P.getGap().set(0,gap);
                    P.setOrder(traindataset.getOrder().get(order));
                    if (PatternIsSubpatternOfSeries(P,series,order)){
                        support++;
                    }
                }
            }
        }
        */
    }


    public boolean PatternIsSubpatternOfSeries(Pattern a, List<Integer> s, int o) {//find out whether pattern is a subpattern of series
        int i = 0;
        int index = 0;
        int gap = 0;
        int j = 0;
        if (a.getOrder() != o) return false;
        for (j = 0, i = 0; j < a.getDseries().size() && i < a.getGap().size(); j++, i++) {
            if (index >= s.size()) return false;
            //if (i == 4 || index == 4)
            //    System.out.println(a + " " + s + " " + s.size() + " " + i + " " + index + " " + gap + " " + o + " " + (index + gap + 1 < s.size() && j < a.getDseries().size()));
            if (a.getDseries().get(j) != s.get(index)) {
                return false;
            }
            gap = a.getGap().get(i);
            index = index + gap + 1;
        }
        return true;
    }


    private boolean PatternCanBeJoin(Pattern a, Pattern b) { //determine whether a b can do join operate
        //System.out.println(b.getDseries().size()+"3 "+b.getGap().size());
        if (a.getOrder() != b.getOrder()) return false;
        if (a.getDseries().size() != b.getDseries().size()) return false;
        Pattern c = new Pattern();
        Pattern d = new Pattern();

        c.getDseries().addAll(a.getDseries());
        d.getDseries().addAll(b.getDseries());
        c.getGap().addAll(a.getGap());
        d.getGap().addAll(b.getGap());

        c.getDseries().remove(0);
        d.getDseries().remove(b.getDseries().size() - 1);
        //if (b.getGap().size() <= 1 || a.getGap().size() <= 1) {
        //    return false;
        //} else
        if (c.getGap().remove(0) != d.getGap().remove(d.getGap().size() - 1)) {
            return false;
        }

        for (int i = 0; i < c.getDseries().size(); i++) {
            int aa = c.getDseries().get(i);
            int bb = d.getDseries().get(i);

            if (aa != bb) return false;
        }


        return true;
    }


    private Pattern PatternJoin(Pattern a, Pattern b) { //do join between a and b from k-patutern to k+1-pattern
        //System.out.println(b.getDseries().size()+" 4"+b.getGap().size());
        Integer Bnumber = b.getDseries().get(b.getDseries().size() - 1);
        Integer Bgap = b.getDseries().get(b.getGap().size() - 1);
        Pattern c = new Pattern();
        c.getDseries().addAll(a.getDseries());
        c.setOrder(a.getOrder());
        c.getGap().addAll(a.getGap());

        c.getDseries().add(Bnumber);
        c.getGap().add(Bgap);
        //a.getDseries().add(b.getDseries().get(b.getDseries().size() - 1));
        //a.getGap().add(b.getGap().get(b.getGap().size() - 1));
        return c;
    }
}
